#Include ../debug.ahk

; desc:  element of queue
class QNode {
  __New(val) {
    this.val := val
    this.next := ''
  }

  static BuyNode(val) {
    return QNode(val)
  }
}

; desc:  queue data structure
class Queue {
  __New() {
    this.head := this.rear := ''
  }

  ; param: Node instance
  ; ret:
  ; desc:  push element into queue
  Add(Node) {
    if !this.head {
      this.head := this.rear := Node
    }
    else {
      this.rear.next := Node
      this.rear := Node
    }
  }

  AddVal(val) {
    Node := QNode(val)
    if !this.head {
      this.head := this.rear := Node
    }
    else {
      this.rear.next := Node
      this.rear := Node
    }
  }

  ; param:
  ; ret:   data of pop-up Node instance
  ; desc:  delete the first node
  Poll() {
    if !this.head
      return
    else {
      data := this.head.val
      this.head := this.head.next
      return data
    }
  }

  ; param:
  ; ret:   typeof this.head.val
  ; desc:  return the value of the first node
  Peek() {
    if !this.head
      return 'null'
    return this.head.val
  }

  ; param:
  ; ret:
  ; desc:
  Traverse() {
    cur := this.head
    list := ''
    while IsObject(cur) {
      list .= cur.val
      cur := cur.next
    }
    return list
  }

  IsEmpty() {
    return (this.head) ? false : true
  }
}

if A_LineFile == A_ScriptFullPath {
  dibug := Debug()

  a := QNode('a')
  b := QNode('b')
  c := QNode.BuyNode('c')

  ; init queue
  q := Queue()

  ; test add
  q.Add(a)
  q.Add(b)
  q.Add(c)
  q.AddVal('d')

  dibug.Join('--traverse-after-add')
  dibug.Join(q.Traverse())

  ; test poll
  q.Poll()
  q.Poll()

  dibug.Join('--traverse-after-poll')
  dibug.Join(q.Traverse())

  dibug.Join('--peek')
  dibug.Join(q.Peek())
  dibug.Join('--isEmpty')
  dibug.Join(q.IsEmpty())

  dibug.Log()
}